package cn.tedu.charging.order.rabbit;

import cn.tedu.charging.order.config.RabbitConfiguration;
import cn.tedu.charging.order.pojo.dto.OrderMQDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class RabbitMQOrderProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendOrder(OrderMQDTO orderMQDTO){
        // 设置RabbitMQ return的回调类 并执行
        /**
         * 确保消息必须被正确路由到队列
         * 如果消息无法路由到任何队列（例如路由键不匹配），会触发返回回调
         */
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnsCallback(returnMessage -> {
            // returnMessage 包含被退掉的信息、消息本身、错误码、错误的消息
            // 退订发生在哪个交换机，发生在哪个路由 key
            log.debug("消息发送失败：{}", returnMessage);
        });

        // 设置 RabbitMQ 的确认 confirm 机制的回调类，保证生产者消息不丢
        /**
         * correlationData：关联数据，可用于关联发送的消息和确认
         * ack：确认标志，true 表示消息已成功投递到 RabbitMQ
         * cause：失败原因，当 ack 为 false 时，包含失败的具体原因
         * 通过这个 Confirm 机制，我们可以确保：
         *      当消息成功投递到 RabbitMQ 时，会收到确认回调
         *      当消息投递失败时，可以记录错误日志并进行相应处理
         *      结合你项目中已有的配置 publisher-confirm-type: correlated 和 ReturnCallback 机制，现在生产者消息的可靠性得到了完整保障。
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            log.debug("RabbitMQ确认回调：correlationData:{},ack:{},cause:{}", correlationData, ack, cause);
            if (ack) {
                log.debug("消息发送成功: correlationData={}", correlationData);
            } else {
                log.error("消息发送失败: correlationData={}, cause={}", correlationData, cause);
            }
        });


        // 第一个参数 队列名称， 第二个参数 RoutingKey， 第三个参数 数据
        rabbitTemplate.convertAndSend(RabbitConfiguration.EXCHANGE_NAME, RabbitConfiguration.ROUTING_KEY, orderMQDTO);
    }

}
